using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using TwitterLib;
using System.Windows.Threading;
using System.Net;
using TwitterCommon;
using System.Collections.ObjectModel;

namespace TwitterViewer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>

    public partial class MainWindow : System.Windows.Window
    {
        #region Fields and Properties

        // Main collection of tweets
        public static Tweets tweets = new Tweets();

        // Main TwitterNet object
        private TwitterNet twitter;

        // Timer used for automatic tweet updates
        private DispatcherTimer refreshTimer = new DispatcherTimer();

        // How often the automatic tweet updates occur.  TODO: Make this configurable
        private TimeSpan refreshInterval = new TimeSpan(0, 2, 0);  // 2 minutes

        // Delegates for placing jobs onto the thread dispatcher.  
        // Used for making asynchronous calls to Twitter so that the UI does not lock up.
        private delegate void NoArgDelegate();
        private delegate void OneArgDelegate(Tweets arg);
        private delegate void AddTweetDelegate(string arg);

        // Settings for the application
        private Properties.Settings AppSettings = Properties.Settings.Default;

        // Collection of statuses
        // TODO: keep a history of statuses
        //private ObservableCollection<string> statuses = new ObservableCollection<string>();

        #endregion

        #region Overrides
        /// <summary>
        /// Override to apply Aero Glass
        /// </summary>
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            // Apply Aero Glass to the entire window
            // TODO: check for Vista?
            GlassHelper.ExtendToEntireFrame(this);
        }
        #endregion

        public MainWindow()
        {
            InitializeComponent();

            // Does the user need to login
            if (string.IsNullOrEmpty(AppSettings.Username))
            {
                Login login = new Login();
                bool? dialogResult = login.ShowDialog();

                // Create TwitterNet class
                if ((bool)dialogResult)
                    // Authenticated user
                    twitter = new TwitterNet(AppSettings.Username, AppSettings.Password);
                else
                {
                    // Unauthenticated user
                    twitter = new TwitterNet();

                    // Can't add new tweet
                    AddButton.IsEnabled = false;
                }
            }
            else
            {
                // Use persisted username and password
                twitter = new TwitterNet(AppSettings.Username, AppSettings.Password);

                // Load previous tweets from disk
                tweets.Load();
            }

            // Set the datacontext
            MainGrid.DataContext = tweets;

            // Dispatch fetching Twitter Timeline
            DelegateUpdate();

            // Setup refresh timer
            refreshTimer.Interval = refreshInterval;
            refreshTimer.Tick += new EventHandler(Timer_Elapsed);
            refreshTimer.Start();

            // Set the default focus
            AddTweetTextBox.Focus();
        }

        #region Methods and Event Handlers

        /// <summary>
        /// Encapsulated method to dispatch fetching new tweets asynchronously
        /// </summary>
        private void DelegateUpdate()
        {
            // Let the user know what's going on
            StatusTextBlock.Text = "Fetching new tweets...";

            // Create a Dispatcher to fetching new tweets
            NoArgDelegate fetcher = new NoArgDelegate(
                this.UpdateTweets);

            fetcher.BeginInvoke(null, null);
        }

        private void Timer_Elapsed(object sender, EventArgs e)
        {
            DelegateUpdate();
        }

        private void UpdateTweets()
        {
            try
            {
                // Schedule the update function in the UI thread.
                MainGrid.Dispatcher.BeginInvoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new OneArgDelegate(UpdateUserInterface), twitter.GetFriendsTimeline(AppSettings.LastUpdated));
            }
            catch (WebException ex)
            {
#if DEBUG
                MessageBox.Show("There was a problem fetching new tweets from Twitter.com. " + ex.Message);
#endif
            }
        }

        private void UpdateUserInterface(Tweets newTweets)
        {
            // Refresh the grid so that relativeTime updates
            MainGrid.DataContext = null;
            MainGrid.DataContext = tweets;

            DateTime lastUpdated = DateTime.Now;
            StatusTextBlock.Text = "Last Updated: " + lastUpdated.ToString();

            AppSettings.LastUpdated = lastUpdated.ToString();
            AppSettings.Save();

            int tweetAdded = 0;

            for (int i = newTweets.Count - 1; i >= 0; i--)
            {
                Tweet tweet = newTweets[i];
                if (!tweets.Contains(tweet))
                {
                    tweets.Insert(0, tweet);
                    tweetAdded++;
                }
            }

            string tweetAddedMsg = string.Empty;

            switch (tweetAdded)
            {
                case 0:
                    tweetAddedMsg = "No new tweets found";
                    break;
                case 1:
                    tweetAddedMsg = "1 new tweet found.";
                    break;
                case 20:
                    tweetAddedMsg = "20+ tweets found.  The latest 20 are shown.";
                    break;
                default:
                    tweetAddedMsg = tweetAdded + " new tweets found";
                    break;
            }
            StatusTextBlock.Text = StatusTextBlock.Text + ". " + tweetAddedMsg;

            if (TweetsListView.SelectedIndex == -1)
                TweetsListView.SelectedIndex = 0;
        }

        private void AddTweet(string text)
        {
            try
            {
                twitter.AddTweet(text);

                // Schedule the update function in the UI thread.
                MainGrid.Dispatcher.BeginInvoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new AddTweetDelegate(UpdatePostUserInterface), text);
            }
            catch (WebException ex)
            {
#if DEBUG
                MessageBox.Show("There was a problem posting your tweet to Twitter.com. " + ex.Message);
#endif
            }
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            StatusTextBlock.Text = "Posting your tweet.";

            // Schedule posting the tweet
            AddButton.Dispatcher.BeginInvoke(
                System.Windows.Threading.DispatcherPriority.Normal,
                new AddTweetDelegate(AddTweet), AddTweetTextBox.Text);
            AddTweetTextBox.Clear();
            AddTweetTextBox.Focus();
        }

        private void RefreshButton_Click(object sender, RoutedEventArgs e)
        {
            DelegateUpdate();
        }

        private void UpdatePostUserInterface(string text)
        {
            StatusTextBlock.Text = "Your tweet was posted successful.";
        }

        private void LoginButton_Click(object sender, RoutedEventArgs e)
        {
            Login login = new Login();
            bool? dialogResult = login.ShowDialog();

            // Create TwitterNet class
            if ((bool)dialogResult)
                twitter = new TwitterNet(AppSettings.Username, AppSettings.Password);
            else
                twitter = new TwitterNet();

            AddButton.IsEnabled = !string.IsNullOrEmpty(AppSettings.Username);

            tweets.Clear();

            DelegateUpdate();
        }

        /// <summary>
        /// Used for parsing Hypertext to hyperlinks
        /// </summary>
        private void TweetTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (TweetTextBlock != null)
            {
                TweetTextBlock.Inlines.Clear();

                string[] words = ((TextBox)sender).Text.Split(' ');

                foreach (string word in words)
                {
                    if (StringUtils.IsHyperlink(word))
                    {
                        try
                        {
                            Hyperlink link = new Hyperlink();
                            link.NavigateUri = new Uri(word);
                            link.Inlines.Add(word);
                            link.Click += Hyperlink_Click;
                            TweetTextBlock.Inlines.Add(link);
                        }
                        catch
                        {
                            TweetTextBlock.Inlines.Add(word);
                        }
                    }
                    else
                        TweetTextBlock.Inlines.Add(word);

                    TweetTextBlock.Inlines.Add(" ");
                }
            }

        }

        /// <summary>
        /// Handler for all hyperlinks. Opens the link in the user's default browser.
        /// </summary>
        void Hyperlink_Click(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());
        }

        #endregion
    }
}